package com.example.analysis.utils;

import org.apache.commons.math3.distribution.ChiSquaredDistribution;
import org.apache.commons.math3.distribution.FDistribution;
import org.apache.commons.math3.stat.inference.MannWhitneyUTest;
import java.util.*;


public class DifferenceAnalysis {
    // 极端组法计算区分度。pValue < 0.05，区分度高
    public static double[] twoGroupAnalysis(List<double[]> groups) {
        // 分组
        double[] highGroup = groups.get(0);
        double[] lowGroup = groups.get(1);
        // 1.正态性检验
        boolean flag = false;
        for (double[] group : groups) {
            double[] ksTest = NormalityTest.ksTest(group);
            if (ksTest[1] <= 0.05) {
                flag = true;
                break;
            }
        }
        if (flag) {
            // 非正态，使用Mann-Whitney U检验
            MannWhitneyUTest mannWhitneyUTest = new MannWhitneyUTest();
            double uValue = mannWhitneyUTest.mannWhitneyU(lowGroup, highGroup);
            double pValue = mannWhitneyUTest.mannWhitneyUTest(lowGroup, highGroup);
            System.out.println("Mann-Whitney U检验：uValue = " + uValue + ", pValue = " + pValue);
            return new double[]{uValue, pValue};
        }
        // 2.方差齐性检验
        double pValue, tValue;
        double leveneTestPValue = LeveneTest.leveneTest(groups, true);
        if (leveneTestPValue >= 0.05) {
            System.out.println("方差齐 --- Student's检验");
            tValue = TTest.calculateStudentsT(lowGroup, highGroup);
            // 自由度
            double df = highGroup.length + lowGroup.length - 2;
            pValue = TTest.calculateTTestPValue(tValue, df);
        } else {
            System.out.println("方差不齐 --- Welch's检验");
            tValue = TTest.calculateWelchT(lowGroup, highGroup);
            // 自由度
            double df = TTest.calculateWelchDF(lowGroup, highGroup);
            pValue = TTest.calculateTTestPValue(tValue, df);
        }
        System.out.println("tValue = " + tValue + ", pValue = " + pValue);
        return new double[]{tValue, pValue};
    }

    // 分组（高低分）
    public static List<double[]> divideGroups(double[] scores, double quantile) {
        Arrays.sort(scores); // 升序排序
        int n = scores.length;
        int groupSize = (int) Math.round(n * quantile);

        // 取后27%为高分组（排序后数组的尾部）
        double[] highGroup = Arrays.copyOfRange(scores, n - groupSize, n);
        // 取前27%为低分组（排序后数组的头部）
        double[] lowGroup = Arrays.copyOfRange(scores, 0, groupSize);
        List<double[]> groups = new ArrayList<>();
        groups.add(highGroup);
        groups.add(lowGroup);
        return groups;
    }

    // 方差分析，不同班级的某门课程差异分析
    public static double[] moreGroupAnalysis(List<double[]> groups) {
        //1.正态性检验
        boolean isNormality = true;
        for (double[] group : groups) {
            double[] doubles = NormalityTest.ksTest(group);
            if (doubles[1] > 0.05) {
                isNormality = false;
                break;
            }
        }
        if (!isNormality) {
            // 非正态，Kruskal-Wallis H检验
            return performKruskalWallis(groups);
        }
        //2.方差齐性检验
        double leveneTest = LeveneTest.leveneTest(groups, true);
        //3.方差分析
        double fValue, pValue;
        if (leveneTest >= 0.05) {
            System.out.println("方差齐 --- ANOVA");
            fValue = OneWayAnova.calculateANOVAFValue(groups);
            pValue = OneWayAnova.calculateANOVAPValue(groups, fValue);
        } else {
            System.out.println("方差不齐 --- Welch's ANOVA");
            double[] temp = welchsAnova(groups);
            fValue = temp[0];
            pValue = temp[1];
        }
        System.out.println("fValue = " + fValue + ", pValue = " + pValue);
        return new double[]{fValue, pValue};
    }

    // 执行 Welch's ANOVA 检验 （p < 0.05，显著）
    private static double[] welchsAnova(List<double[]> groups) {
        int k = groups.size();
        int[] n = new int[k];
        double[] means = new double[k];
        double[] variances = new double[k];
        int N = 0;

        // 计算每组的样本大小、均值和方差
        for (int i = 0; i < k; i++) {
            double[] group = groups.get(i);
            n[i] = group.length;
            N += n[i];
            means[i] = ComCalcUtils.calcMean(group);
            variances[i] = ComCalcUtils.calcVariance(group);
        }

        // 计算加权均值
        double weightedSum = 0;
        double weightSum = 0;
        for (int i = 0; i < k; i++) {
            double weight = n[i] / variances[i];
            weightedSum += weight * means[i];
            weightSum += weight;
        }
        double weightedMean = weightedSum / weightSum;

        // 计算 Welch's F 统计量
        double numerator = 0;
        for (int i = 0; i < k; i++) {
            double weight = n[i] / variances[i];
            numerator += weight * Math.pow(means[i] - weightedMean, 2);
        }
        numerator /= (k - 1);

        double denominator = 1;
        double sumTerm = 0;
        for (int i = 0; i < k; i++) {
            sumTerm += Math.pow(1 - (double) n[i] / N, 2) / (n[i] - 1);
        }
        denominator += ((double) (2 * (k - 2)) / (k * k - 1)) * sumTerm;

        double F = numerator / denominator;

        // 计算自由度
        int df1 = k - 1;
        double df2 = (k * k - 1) / sumTerm;

        // 计算 p 值
        FDistribution fDistribution = new FDistribution(df1, df2);
        double pValue = 1 - fDistribution.cumulativeProbability(F);
        return new double[]{F, pValue};
    }


    /**
     * Kruskal-Wallis检验 （p < 0.05，显著）卡方分布
     */
    private static double[] performKruskalWallis(List<double[]> groups) {
        List<Double> allData = new ArrayList<>();
        for (double[] group : groups) {
            for (double one : group) {
                allData.add(one);
            }
        }
        Collections.sort(allData);

        // 计算秩次
        Map<Double, Double> rankMap = calculateRanks(allData);
        double totalN = allData.size();

        // 计算每组秩和
        double H = 0.0;
        for (double[] group : groups) {
            double rankSum = 0.0;
            for (Double x : group) rankSum += rankMap.get(x);
            H += Math.pow(rankSum, 2) / group.length;
        }
        H = (H * 12) / (totalN * (totalN + 1)) - 3 * (totalN + 1);

        int df = groups.size() - 1;
        ChiSquaredDistribution chiSquaredDistribution = new ChiSquaredDistribution(df);
        double pValue = 1 - chiSquaredDistribution.cumulativeProbability(H);
        System.out.println("非正态，进行Kruskal-Wallis检验：HValue = " + H + ", pValue = " + pValue);
        return new double[]{H, pValue};
    }

    // 计算秩和
    private static Map<Double, Double> calculateRanks(List<Double> sortedData) {
        Map<Double, Double> rankMap = new HashMap<>();
        int i = 0;
        while (i < sortedData.size()) {
            int j = i;
            while (j < sortedData.size() && sortedData.get(j).equals(sortedData.get(i))) j++;
            double rank = (i + j + 1) / 2.0; // 平均秩次
            for (int k = i; k < j; k++) rankMap.put(sortedData.get(k), rank);
            i = j;
        }
        return rankMap;
    }
}
